# PROTOTYPE, NOT TEST-COVERED!

import random

class _scheduled_module :
    def __init__ ( self , module , arg_scheduler ) :
        self . _scheduler = _module_scheduler ( arg_scheduler )
        self . _module = module
        for attr_name in dir ( module ) :
            if not attr_name . startswith ( '_' ) :
                module_method = getattr ( module , attr_name )
                setattr ( self , attr_name , self . _method_wrapper ( module_method ) )
    def _method_wrapper ( self , method ) :
        def call_method ( * args ) :
            self . _scheduler . push_message ( method , * args )
        return call_method
        
class _module_scheduler :
    def __init__ ( self , arg_scheduler ) :
        arg_scheduler . _add_module_scheduler ( self )
        self . _roundrobin = [ ]
        self . _inside_run_loop = False
    def run_single_scheduler ( self ) :
        if not self . _inside_run_loop :
            self . _inside_run_loop = True            
            current_robin = self . _roundrobin
            self . _roundrobin = [ ]
            current_robin . reverse ( )
            while len ( current_robin ) > 0 :
                current_robin . pop ( ) . run ( )
            self . _inside_run_loop = False
    def push_message ( self , func , * args ) :
        self . _roundrobin += [ _roundrobin_entry ( func , args ) ]
    def messages_count_in_queue ( self ) :
        return len ( self . _roundrobin )

class _roundrobin_entry :
    def __init__ ( self , func , args ) :
        self . _func = func
        self . _args = args
    def run ( self ) :
        self . _func ( * self . _args )

class scheduler :            
    def __init__ ( self ) :
        self . _all_schedulers = [ ]
    def module ( self , module ) :
        return _scheduled_module ( module , self )
    def run ( self , func , * args ) :
        func ( * args )
        self . _run_scheduler ( )
    def _add_module_scheduler ( self , module_scheduler ) :
        self . _all_schedulers += [ module_scheduler ]
    def _scheduled_messages_count ( self ) :
        count = 0
        for s in self . _all_schedulers :
            count += s . messages_count_in_queue ( )
        return count
    def _run_scheduler ( self ) :
        while self . _scheduled_messages_count ( ) > 0 :
            schedulers = self . _all_schedulers [ : ]
            random . shuffle ( schedulers )
            for s in schedulers :
                s . run_single_scheduler ( )
